package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Piece struct {
	LineArr [4]int //idx:0-left,1-top,2-right,3-bottom;value:0-flat,-1-in,1-out
}

func (p *Piece) CheckRight(dst *Piece) int {
	if dst == nil {
		return p.LineArr[2]
	}
	return p.LineArr[2] + dst.LineArr[0]
}

func (p *Piece) CheckBottom(dst *Piece) int {
	if dst == nil {
		return p.LineArr[3]
	}
	return p.LineArr[3] + dst.LineArr[1]
}

func (p *Piece) IsFlat(rightP, bottomP *Piece) bool {
	return p.CheckRight(rightP)+p.CheckBottom(bottomP) == 0
}

func CheckPuzzle(arr []*Piece, width, height int) bool {
	for i := 0; i < height; i++ {
		for j := 0; j < width; j++ {
			idx := i*width + j
			if i == 0 && arr[idx].LineArr[1] != 0 {
				fmt.Printf("Not Flat Row%d, Col%d\n", i, j)
				return false
			}
			if j == 0 && arr[idx].LineArr[0] != 0 {
				fmt.Printf("Not Flat Row%d, Col%d\n", i, j)
				return false
			}
			var rightP, bottomP *Piece = nil, nil
			if j+1 < width {
				rightP = arr[idx+1]
			}
			if i+1 < height {
				bottomP = arr[idx+width]
			}
			if !arr[idx].IsFlat(rightP, bottomP) {
				fmt.Printf("Not Flat Row%d, Col%d\n", i, j)
				return false
			}
		}
	}
	fmt.Printf("All Flat!\n")
	return true
}

func main() {
	rand.Seed(time.Now().UnixNano())
	width := rand.Intn(3)+2
	height := rand.Intn(3)+2
	arr := make([]*Piece, width*height)
	for i := 0; i < height; i++ {
		for j := 0; j < width; j++ {
			idx := i*width + j
			arr[idx] = &Piece{}
			for k := 0; k < 4; k++ {
				arr[idx].LineArr[k] = rand.Intn(3) - 1
			}
			fmt.Printf("%v ", arr[idx])
		}
		fmt.Println()
	}
	CheckPuzzle(arr, width, height)

	arr2 := [4]*Piece{
		{
			LineArr: [4]int{0,0,1,1},
		},
		{
			LineArr: [4]int{-1,0,0,-1},
		},
		{
			LineArr: [4]int{0,-1,1,0},
		},
		{
			LineArr: [4]int{-1,1,0,0},
		},
	}
	CheckPuzzle(arr2[:],2,2)
}